package com.guigu.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import com.guigu.base.entity.dto.AgencyScopeDto;
import com.guigu.base.entity.dto.CourierScopDto;
import com.guigu.order.entity.Order;
import com.guigu.order.entity.OrderCargo;
import com.guigu.order.entity.OrderLocation;
import com.guigu.order.feign.BaseFeign;
import com.guigu.order.feign.WorkFeign;
import com.guigu.order.service.OrderLocationService;
import com.guigu.order.service.OrderService;
import com.guigu.order.service.WeChatService;
import com.guigu.order.utils.HttpClient;
import com.guigu.order.utils.PathUtils;
import com.guigu.tms.exception.TmsException;
import com.guigu.tms.result.R;
import com.guigu.tms.result.ResultCode;
import com.guigu.work.dto.TaskPickupDispatchDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName:WeChatServiceImpl
 * @Description://TODO
 * @Author:taoLong
 * @Date:2021/11/16:15:30 星期二
 * @email:2391611102@qq.com or 2391611102qq@gmail.com
 */
@Service
@Slf4j
public class WeChatServiceImpl implements WeChatService {

    @Value("${weixin.pay.appid}")
    private String appId;
    @Value("${weixin.pay.partner}")
    private String partner;
    @Value("${weixin.pay.partnerkey}")
    private String partnerKey;
    @Value("${weixin.pay.notifyurl}")
    private String notifYurl;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private OrderService orderService;
    @Autowired
    private WorkFeign workFeign;
    @Autowired
    private BaseFeign baseFeign;

    @Autowired
    private OrderLocationService orderLocationService;

    /**
     * 根据订单id生成微信支付二维码
     *
     * @param orderId
     * @return
     */
    public Map<String, Object> createAQRCode(String orderId, String orderNo) {
        try {
            /**
             * 获取订单信息
             */
            Order order = orderService.getById(orderId);
            R<Map> r = orderService.getOrderCargoVoAndOrderLocationVoInfoByOrderId(orderId);
            System.out.println("r = " + r);
            OrderCargo cargo = (OrderCargo) r.getData().get("orderCargo");
            /**
             * 使用map设置生产二维码需要参数
             */
            Map<String, String> map = new HashMap<>();
            /**
             * appId
             */
            map.put("appid", appId);
            map.put("mch_id", partner);
            map.put("nonce_str", WXPayUtil.generateNonceStr());
            map.put("body", cargo.getName());

            map.put("out_trade_no", orderNo);
            map.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue() + "");
            map.put("spbill_create_ip", "127.0.0.1");
            map.put("notify_url", notifYurl);
            map.put("trade_type", "NATIVE");
            //发送httpclient请求,传递xml格式
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            //设置参数
            client.setXmlParam(WXPayUtil.generateSignedXml(map, partnerKey));
            client.setHttps(true);
            //执行请求发送
            client.post();
            //得到返回的结果,返回的结果是xml格式,所以我们需要将它转换成map集合
            String content = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            System.out.println("resultMap = " + resultMap);

            //log.info("返回结果集为:" + String.valueOf(resultMap));
            //对map最后的封装
            Map map2 = new HashMap<>();
            map2.put("out_trade_no", order.getId());
            map2.put("orderCargoName", cargo.getName());
            map2.put("total_fee", order.getAmount() + "");
            map2.put("result_code", resultMap.get("result_code"));//返回二维码操作的状态
            map2.put("code_url", resultMap.get("code_url"));//返回二维码地址
            return map2;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成二维码后,查询支付时的状态(支付中,支付取消等等)
     *
     * @param orderId
     * @return
     */
    @Override
    public Map<String, String> queryPayStatus(String orderId, String orderNo) {
        try {
            //1、封装参数
            Map m = new HashMap<>();
            m.put("appid", appId);
            m.put("mch_id", partner);
            m.put("out_trade_no", orderNo);
            m.put("nonce_str", WXPayUtil.generateNonceStr());
            // m.put("courseId",)
            //2、设置请求
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setXmlParam(WXPayUtil.generateSignedXml(m, partnerKey));
            client.setHttps(true);
            client.post();
            //3、返回第三方的数据
            String xml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
            //6、转成Map
            //7、返回
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new TmsException(ResultCode.ERROR_CODE, "支付失败!");
        }
    }

    /**
     * 派单给当前范围的快递员
     *
     * @param orderId
     * @return
     */
    @Override
    @GlobalTransactional(name = "order_dispatch", rollbackFor = Exception.class)
    public R dispatch(String orderId) {
        /**
         * 支付成功,则修改订单状态,并从redis中删除数据全局唯一Id
         */
        redisTemplate.delete(orderId);
        /**
         * 修改订单状态
         */
        orderService.paySuccess(orderId);

        /**
         * 增加取件任务信息表
         */
        TaskPickupDispatchDTO dto = new TaskPickupDispatchDTO();
        dto.setOrderId(orderId);
        /**
         * 取件任务
         */
        dto.setTaskType(1);
        /**
         * 根据订单id查询出订单当前网点
         */
        String agencyId = orderService.getById(orderId).getCurrentAgencyId();
        dto.setAgencyId(agencyId);
        dto.setStatus(1);
        /**
         * 设置创建时间
         */
        dto.setCreateTime(new Date());
        /**
         * 1.当前机构范围
         */
        AgencyScopeDto data = baseFeign.findByAgencyScopeId(agencyId).getData();

        /**
         * 2.查询当前订单位置,是否在该机构范围内
         */
        QueryWrapper<OrderLocation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderId);
        OrderLocation location = orderLocationService.getOne(queryWrapper);
        /**
         * 2.1获取当前订单位置
         */
        String sendLocation = location.getSendLocation();
        /**
         * 2.2分割为经度和纬度字符串
         */
        String longitude = sendLocation.substring(0, sendLocation.indexOf(","));
        String latitude = sendLocation.substring(sendLocation.indexOf(",") + 1);
        /**
         * 2.3判断该订单是否在机构范围内
         */
        boolean flag = PathUtils.isPoint(data.getMutiPoints(), Double.valueOf(longitude), Double.valueOf(latitude));
        /**
         * 2.4如果等于则查询该机构范围内的快递员来判断是否在该快递员工作范围内
         */
        if (flag) {
            /**
             *2.4.1 查询该机构范围所以下的快递员
             */
            log.info("机构id为:{}", agencyId);
            R<List<CourierScopDto>> r = baseFeign.findAllCourierScope(agencyId, "");

            log.info("r为{}", r);
            List<CourierScopDto> list = r.getData();
            /**
             * 为null,直接改为人工配送
             */
            R x = courierScopeIsNull(dto, list);
            log.error("人工配送");
            if (x != null) return x;

            /**
             * 不为null,设置为快递员id,已经改为已分配
             */
            R x1 = courierScopeIsNotNull(dto, longitude, latitude, list);
            log.info("安排快递员成功!");
            if (x1 != null) return x1;

            /**
             * 如果不在快递员的工作范围内,则设置为人工分配
             */
            log.error("不在快递员工作范围内");
            dto.setAssignedStatus(3);
            workFeign.save(dto);

            return new R("2003", "支付成功!", false);
        }
        /**
         *如果不在当前机构范围内,那么则直接为人工分配
         */
        log.error("不在当前机构范围内");
        dto.setAssignedStatus(3);
        workFeign.save(dto);
        return new R("2003", "支付成功!", false);
    }

    @Nullable
    private R courierScopeIsNotNull(TaskPickupDispatchDTO dto, String longitude, String latitude, List<CourierScopDto> list) {
        /**
         * 如果不为null,则循环判断每一个快递员的工作范围
         */
        for (CourierScopDto scopDto : list) {
            boolean b = PathUtils.isPoint(scopDto.getMutiPoints(), Double.valueOf(longitude), Double.valueOf(latitude));
            if (b) {
                /**
                 * 设置快递员Id
                 */
                dto.setCourierId(scopDto.getUserId());
                /***
                 * 设置为已分配状态
                 */
                dto.setAssignedStatus(2);
                /**
                 * 实际开始时间
                 */
                dto.setActualStartTime(new Date());
                workFeign.save(dto);
                return new R("2003", "支付成功!", false);
            }
        }
        return null;
    }

    @Nullable
    private R courierScopeIsNull(TaskPickupDispatchDTO dto, List<CourierScopDto> list) {
        /**
         * 为null则设置为人工分配
         */
        if (CollUtil.isEmpty(list)) {
            /**
             * 设置为人工分配
             */
            dto.setAssignedStatus(3);
            workFeign.save(dto);
            return new R("2003", "支付成功!", false);
        }
        return null;
    }
}
